import { CursorFloatDiv, CursorInfo, Event, extendClassProps, nextAnimateFrame, ObservableArray, Processing, react, reactArray, ReactivePropsToNativePropsAndChanged, track } from "xbsj-base";
import { ESJArcType, ESJVector3DArray, ESJVector4D } from "earthsdk3";
import { CzmPolyline } from "@czmSrc/CzmObjects";
import { ESCesiumViewer } from "@czmSrc/ESCesiumViewer";
import { EditingPoint } from "./EditingPoint";
import { Editing } from "../Editing";
export type EditingStatusType = 'Adding' | 'Modifying' | 'Modifying_Point' | 'None';

export class MultiPointsEditing extends Editing {
    static readonly baseImageUrl = `\${earthsdk3-assets-script-dir}/assets/img/`;
    static override defaults = {
        ...Editing.defaults,
        debug: false,
        polylineShow: false,
        polylineWidth: 1,
        polylineColor: [1, 1, 1, 1],
        polylineArcType: 'GEODESIC',
        maxPointsNum: Number.MAX_SAFE_INTEGER,
        loop: false,
        firstControlPointImageUrl: MultiPointsEditing.baseImageUrl + 'point-green.png',
        otherControlPointImageUrl: MultiPointsEditing.baseImageUrl + 'point-yellow.png',
    }
    private _editingPoints = this.disposeVar(new ObservableArray<EditingPoint>());
    get editingPoints() { return this._editingPoints; }

    private _cancelEvent = this.disposeVar(new Event());
    get cancelEvent() { return this._cancelEvent; }
    cancel() { this._cancelEvent.emit(); }

    private _currentProcess: Processing | undefined;
    get currentProcess() { return this._currentProcess; }
    set currentProcess(value: Processing | undefined) { this._currentProcess = value }

    private _menuPoiEnabled = this.disposeVar(react<boolean>(false));
    get menuPoiEnabled() { return this._menuPoiEnabled.value; }
    set menuPoiEnabled(value: boolean) { this._menuPoiEnabled.value = value; }
    get menuPoiEnabledChanged() { return this._menuPoiEnabled.changed; }

    private _status = this.disposeVar(react<EditingStatusType>('None'));
    get status() { return this._status.value; }
    get statusChanged() { return this._status.changed; }
    set status(value: EditingStatusType) { this._status.value = value; }
    /**
     * 每次调用都会创建一个新的数组，谨慎使用，避免影响性能！
     * @returns 
     */
    getPositions() {
        const positions: ESJVector3DArray = [];
        for (let e of this._editingPoints) {
            e.position && positions.push([...e.position]);
        }
        return positions;
    }
    resetPositions(value?: ESJVector3DArray): boolean {
        if (this.enabled ?? MultiPointsEditing.defaults.enabled) {
            console.warn(`MultiPointsEditing.resetPositions error: this.enabled === true`);
            return false;
        }
        const newPositions = value || [];
        if (newPositions.length === this.editingPoints.length) {
            if (newPositions.every((e, i) => e.every((ee, ii) => {
                const p = this.editingPoints.get(i);
                return p.position && (p.position[ii] === ee);
            }))) {
                // 如果完全相等，则不进行赋值！
                return false;
            }
        }
        return true;
    }
    forceResetPositions(value?: ESJVector3DArray) {
        if (this.enabled ?? MultiPointsEditing.defaults.enabled) {
            this.enabled = false;
        }
        this.resetPositions(value);
    }
    get positions() { return this.getPositions(); }
    set positions(value: ESJVector3DArray) { this.resetPositions(value); }
    private _positionsChanged = this.ad(new Event());
    get positionsChanged() { return this._positionsChanged; }

    get czmViewer() { return this._czmViewer; }

    private _cursorInfo?: CursorInfo<CursorFloatDiv>;
    get cursorInfo() { return this._cursorInfo; }
    constructor(private _czmViewer: ESCesiumViewer) {
        super();
        this.enabled = false; // 默认为false
        // 地图效果--线,标注
        this.createPolyline(_czmViewer);
        this._createCursorInfo(_czmViewer);
        this.dispose(() => this.resetPositions());
        this.dispose(() => this.editingPoints.length = 0);
        this.dispose(this.editingPoints.changedEvent.disposableOn(() => this.positionsChanged.emit()));
        this.dispose(this.editingPoints.toChangeEvent.disposableOn(changedInfos => {
            for (let { start, deleteCount, items } of changedInfos) {
                for (const e of items) {
                    e.menuPoi.enabled = this.menuPoiEnabled ?? false;
                }
                for (let i = start; i < start + deleteCount; ++i) {
                    const toDelEditor = this.editingPoints.get(i);
                    toDelEditor.destroy();
                }
            }
        }));
        // menuPoiEnabled属性变化时，同步设置editingPoints中的menuPoi的enabled属性
        this.dispose(this.menuPoiEnabledChanged.disposableOn(() => {
            for (let e of this.editingPoints) {
                e.menuPoi.enabled = this.menuPoiEnabled ?? false;
            }
        }));
        this.dispose(_czmViewer.dblclickEvent.don(e => {
            // 左键双击后，执行取消操作
            this.ad(nextAnimateFrame(() => {
                if (e.pointerEvent?.button === 0 && this.enabled && this.currentProcess) {
                    this.currentProcess.cancel();
                }
            }))
        }));
        this.dispose(this.enabledChanged.disposableOn(enabled => {
            if (!this._currentProcess) return;
            if (enabled) {
                this._currentProcess.restart();
            } else {
                this._currentProcess.isRunning && this._currentProcess.cancel();
            }
        }));
        {
            const updateLineShow = () => {
                this.polylineShow = this.czmViewer.editingLineShow;
            }
            updateLineShow();
            this.ad(this.czmViewer.editingLineShowChanged.don(updateLineShow));
        }
    }
    public createPolyline(czmViewer: ESCesiumViewer) {
        const polyline = this.ad(new CzmPolyline(czmViewer));

        this.ad(track([polyline, 'color'], [this, 'polylineColor']))
        this.ad(track([polyline, 'width'], [this, 'polylineWidth']))
        this.ad(track([polyline, 'show'], [this, 'polylineShow']))
        this.ad(track([polyline, 'arcType'], [this, 'polylineArcType']))
        this.ad(track([polyline, 'loop'], [this, 'loop']));
        {
            const update = () => {
                const tempPos = [] as ESJVector3DArray;
                for (const pos of this.getPositions()) {
                    pos[2] -= czmViewer.editingHeightOffset ?? 0;
                    tempPos.push(pos);
                }
                polyline.positions = tempPos;
            }
            update();
            this.ad(this.positionsChanged.don(update));
        }
    }
    private _createCursorInfo(czmViewer: ESCesiumViewer) {
        const cursorInfo = this._cursorInfo = this.ad(new CursorInfo(czmViewer.container as HTMLDivElement, CursorFloatDiv));
        {
            this.dispose(this.statusChanged.disposableOn(() => {
                const status = this.status;
                if (!cursorInfo) return;
                if (!this.hideCursorInfo) {
                    cursorInfo.show = false;
                    return;
                }
                if (status === 'Adding') {
                    cursorInfo.text = `右键/BackSpace键：删除上一个控制点；Esc键或左键双击：退出添加状态，进入修改状态`;
                    cursorInfo.show = true;
                } else if (status === 'Modifying') {
                    cursorInfo.text = `Esc键或左键双击：退出编辑状态`;
                    cursorInfo.show = true;
                } else if (status === 'Modifying_Point') {
                    cursorInfo.text = `Esc键或左键双击：退出编辑状态`;
                    cursorInfo.show = true;
                } else if (status === 'None') {
                    cursorInfo.text = '';
                    cursorInfo.show = false;
                }
            }));
        }
    }
}
export namespace MultiPointsEditing {
    export const createDefaultProps = () => ({
        ...Editing.createDefaultProps(),
        loop: false,
        debug: false,
        polylineShow: true,
        polylineWidth: 1,
        polylineColor: reactArray<ESJVector4D>([1, 1, 1, 1]),
        polylineArcType: 'GEODESIC' as ESJArcType,
        maxPointsNum: Number.MAX_SAFE_INTEGER,
        firstControlPointImageUrl: MultiPointsEditing.baseImageUrl + 'point-green.png',
        otherControlPointImageUrl: MultiPointsEditing.baseImageUrl + 'point-yellow.png',
        hideCursorInfo: false,
        middlePointShow: true,
    })
}
extendClassProps(MultiPointsEditing.prototype, MultiPointsEditing.createDefaultProps);
export interface MultiPointsEditing extends ReactivePropsToNativePropsAndChanged<ReturnType<typeof MultiPointsEditing.createDefaultProps>> { }